import axios from 'axios'
import qs from 'qs'
import { DeviceEventEmitter } from 'react-native'
import { CommonToast } from './ToastUtil'
import { baseURL } from 'src/config/index'
import store from 'src/store'
import { DO_REQUEST_AUTH_TOKEN_ACTION } from 'src/store/actions/userinfo'
import NavigationUtil from './NavigationUtil'

/* token监听处理 begin */
let {
  userinfo: { access_token: token, token_type: bear, userId, refresh_token: refreshToken },
} = store.getState()
// console.log('RequestUnit !!!!!!! ', token, bear, userId, refreshToken)
store.subscribe(handleUserInfoChange)

function handleUserInfoChange() {
  const {
    userinfo: { access_token: newToken, token_type: newBear, userId: newUserId, refresh_token: newRefreshToken },
    company
  } = store.getState()
  if (userId !== newUserId || token !== newToken || bear !== newBear || refreshToken !== newRefreshToken) {
    token = newToken
    bear = newBear
    userId = newUserId
    refreshToken = newRefreshToken
    // console.log('handleUserInfoChange!!!!!!! CHANGEED', token, bear, userId, refreshToken)
  }
}
const REFRESHTOKENING = 'REFRESHTOKENING' // DeviceEventEmitter 刷新token
global.isRefreshTokening = false
/* token监听处理 end */

axios.defaults.baseURL = baseURL
axios.defaults.headers = {
  'Content-Type': 'application/x-www-form-urlencoded',
  Accept: 'application/json, text/plain, */*',
}
axios.defaults.timeout = 10000
// 请求拦截处理
axios.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    if (token && bear && !config.headers.Authorization) {
      config.headers.Authorization = `${bear} ${token}`
    }
    if (userId && !config.headers.userId) {
      config.headers.userId = userId
    }
    return config
  },
  error => {
    // 对请求错误做些什么
    CommonToast('网络请求失败')
    return Promise.reject(error)
  }
)

// 返回拦截处理
axios.interceptors.response.use(
  response => {
    // 对响应数据做点什么
    if (!response.data) {
      return Promise.reject(new Error('响应内容为空'))
    }
    const { code } = response.data
    if (code === 401 && (global.isRefreshTokening || refreshToken)) {
      if (response.config.url.indexOf('auth/token') !== -1) {
        return
      }
      const oldToken = token
      if (!global.isRefreshTokening) {
        global.isRefreshTokening = true
        console.log('store.dispatch(DO_REQUEST_AUTH_TOKEN_ACTION) --->begin')
        // 去刷新token
        const params = {
          refresh_token: refreshToken,
          grant_type: 'refresh_token'
        }
        store.dispatch(DO_REQUEST_AUTH_TOKEN_ACTION({
          params
        })).finally(() => {
          console.log('store.dispatch(DO_REQUEST_AUTH_TOKEN_ACTION) --->end')
          global.isRefreshTokening = false
          DeviceEventEmitter.emit(REFRESHTOKENING)
        })
      }
      // 正在刷新token中
      console.log('DeviceEventEmitter.addListener(REFRESHTOKENING) --->subscription', response.config.url)
      const subscription = DeviceEventEmitter.addListener(REFRESHTOKENING, () => {
        console.log('DeviceEventEmitter.addListener(REFRESHTOKENING) --->unsubscription', response.config.url)
        if (!global.isRefreshTokening) {
          subscription.remove()
        }
        if (token && oldToken !== token) {
          const config = response.config
          config.headers.Authorization = ''
          return axios(config)
        } else {
          return Promise.reject(new Error(response.data.message))
        }
      })
    } else if (code && code === 402) {
      // 去登陆
      NavigationUtil.navigate(`OneLogin`)
      return Promise.reject(new Error(response.data.message))
    } else if (code && code !== 200 && code !== 414 && code !== 102 && code !== 101 && code !== 100) {
      const { data: { message }, config: { headers: { noToast = false } } } = response
      message && !noToast && CommonToast(message)
      return Promise.reject(new Error(response.data.message))
    } else {
      return response.data
    }
  },
  error => {
    // 对响应错误做点什么
    if (!error.response) {
      CommonToast('网络走丢了')
    }
    console.warn('网络请求失败', error)
    return Promise.reject(error)
  }
)

export const get = ({ url, params, headers = {} }) => {
  return axios({
    method: 'get',
    url,
    headers,
    params
  })
}
export const post = ({ url, params, query, headers = {} }) => {
  return axios({
    method: 'post',
    url: urlByAppendingParams(url, query),
    data: qs.stringify(params),
    headers
  })
}
export const postjson = ({ url, params, query }) => {
  return axios({
    method: 'post',
    url: urlByAppendingParams(url, query),
    headers: {
      'Content-Type': 'application/json'
    },
    data: params
  })
}
export const postFormData = ({ url, params, query }) => {
  const { uri, type, mime } = params
  const formData = new FormData()
  const file = { uri, name: uri.split('/').pop(), type: mime }
  formData.append('image', file)
  formData.append('type', type)
  return axios({
    method: 'post',
    url: urlByAppendingParams(url, query),
    data: formData
  })
}

export const put = ({ url, params, query }) => {
  return axios({
    method: 'put',
    url: urlByAppendingParams(url, query),
    data: qs.stringify(params)
  })
}
export const putjson = ({ url, params, query }) => {
  return axios({
    method: 'put',
    url: urlByAppendingParams(url, query),
    headers: {
      'Content-Type': 'application/json'
    },
    data: params
  })
}
export const deleteReq = ({ url, params, query }) => {
  return axios({
    method: 'delete',
    url: urlByAppendingParams(url, query),
    data: qs.stringify(params)
  })
}
export const deleteJson = ({ url, params, query }) => {
  return axios({
    method: 'delete',
    url: urlByAppendingParams(url, query),
    headers: {
      'Content-Type': 'application/json'
    },
    data: params
  })
}
export function urlByAppendingParams(url, query) {
  if (!query) {
    return url
  }
  let result = url
  if (result.substr(result.length - 1) !== '?') {
    result = result + `?`
  }
  for (const key in query) {
    const value = query[key]
    result += `${encodeURIComponent(key)}=${encodeURIComponent(value)}&`
  }
  result = result.substring(0, result.length - 1)
  return result
}
